﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;

namespace FileDuplicateRemover.Core
{
    public class DirectoryEntity : BaseEntity
    {
        public long TotalEntityCount { get; set; }

        public EntityList EntityList { get; set; }

        private DateTime? _Created = null;
        public override DateTime Created
        {
            get
            {
                if (_Created == null)
                {
                    _Created = Directory.GetCreationTime(this.FullName);
                }

                return _Created.Value;
            }
        }

        public DirectoryEntity(string fullName) : base(fullName)
        {
            this.EntityList = new EntityList();
        }

        public DirectoryEntity()
            : this(null)
        {
        }

        public override bool Equals(BaseEntity other)
        {
            if (other != null && other is DirectoryEntity)
                return EqualsCore(other as DirectoryEntity);
            else
                return false;
        }

        private bool EqualsCore(DirectoryEntity de)
        {
            bool res = this == de;

            if (!res)
            {
                res = this.TotalLength == de.TotalLength && this.TotalEntityCount == de.TotalEntityCount/* && this.EntityList.Count == de.EntityList.Count*/;

                if (res)
                {
                    res = HardCompare(de);
                }
            }

            return res;
        }

        private class CompareFileEntity : IComparer<FileEntity>
        {
            public int Compare(FileEntity x, FileEntity y)
            {
                int res = Comparer<long>.Default.Compare(x.TotalLength, y.TotalLength);

                if(res == 0)
                {
                    for (int i = 0; i < x.Hash.Length; i++) // TODO this.Hash.SequenceEqual(fe.Hash);
                    {
                        res = Comparer<byte>.Default.Compare(x.Hash[i], y.Hash[i]);
                        if (res != 0)
                            break;
                    }
                }

                return res;
            }
        }

        private class CompareDirectoryEntity : IComparer<DirectoryEntity>
        {
            public int Compare(DirectoryEntity x, DirectoryEntity y)
            {
                int res = Comparer<long>.Default.Compare(x.TotalLength, y.TotalLength);

                if (res == 0)
                {
                    res = Comparer<long>.Default.Compare(x.TotalEntityCount, y.TotalEntityCount);

                    if (res == 0)
                    {
                        //res = Comparer<byte[]>.Default.Compare(x.Hash, y.Hash);
                    }
                }

                return res;
            }
        }

        private bool CompareFileList(List<FileEntity> fileList1, List<FileEntity> fileList2)
        {
            bool res = fileList1.Count == fileList2.Count;

            if (res)
            {
                fileList1 = fileList1.OrderBy(e => e, new CompareFileEntity()).ToList();
                fileList2 = fileList2.OrderBy(e => e, new CompareFileEntity()).ToList();

                for (int i = 0; i < fileList1.Count; i++)
                {
                    res = fileList1[i].Equals(fileList2[i]);

                    if (!res)
                        break;
                }
            }

            return res;
        }

        private bool CompareDirectoryList(List<DirectoryEntity> dirList1, List<DirectoryEntity> dirList2)
        {
            bool res = dirList1.Count == dirList1.Count;

            if (res)
            {
                long totalEntityCountInList1 = dirList1.Sum(d => d.TotalEntityCount);
                long totalEntityCountInList2 = dirList2.Sum(d => d.TotalEntityCount);

                res = totalEntityCountInList1 == totalEntityCountInList2;

                if (res)
                {
                    dirList1 = dirList1.OrderBy(e => e, new CompareDirectoryEntity()).ToList();
                    dirList2 = dirList2.OrderBy(e => e, new CompareDirectoryEntity()).ToList();

                    for (int i = 0; i < dirList1.Count; i++)
                    {
                        res = dirList1[i].Equals(dirList2[i]);

                        if (!res)
                            break;
                    }
                }
            }

            return res;
        }


        private bool HardCompare(DirectoryEntity de)
        {
            bool res = this.EntityList.Count == de.EntityList.Count; // Сравнить список файлов и каталогов по длине

            if(res)
            {
                res = CompareFileList(
                    this.EntityList.Where(e => e is FileEntity).Cast<FileEntity>().ToList(),
                    de.EntityList.Where(e => e is FileEntity).Cast<FileEntity>().ToList()
                    );

                if (res)
                {
                    res = CompareDirectoryList(
                        this.EntityList.Where(e => e is DirectoryEntity).Cast<DirectoryEntity>().ToList(),
                        de.EntityList.Where(e => e is DirectoryEntity).Cast<DirectoryEntity>().ToList()
                        );
                }
            }

            return res;
        }
    }
}
